package adsi.server;

import adsi.persistence.*;
import org.json.*;
import java.util.*;
import adsi.domain.*;
import adsi.optimization.Optimizator;
import adsi.utils.*;

public class EquipmentsLogic {

    private final static EquipmentsLogic instance = new EquipmentsLogic();
    private DataServiceImpl ds;
    private MaintenanceFactory factory;

    private EquipmentsLogic() {
        factory = MaintenanceFactory.getInstance();
        ds = DataServiceImpl.getInstance();
    }

    public static EquipmentsLogic getInstance() {
        return instance;
    }

    public boolean hasValidParameters(String[] keys, JSONObject parameters) throws JSONException {
        StringBuilder message = new StringBuilder();
        Map<String, String> types = new HashMap();
        Map<String, Object> params = new HashMap();

        types.put("id", "int");
        types.put("tail-number", "String");
        types.put("delivered", "boolean");
        types.put("drop-date", "date");
        types.put("available-date", "date");
        types.put("created-from", "date");
        types.put("created-to", "date");
        types.put("dropped-from", "date");
        types.put("dropped-to", "date");
        types.put("available-from", "date");
        types.put("available-to", "date");

        try {
            for (String k : keys) {
                String t = types.get(k);
                params.put(k, null);

                System.out.println(k);

                if (t.equals("int")) {
                    params.put(k, parameters.getInt(k));
                } else if (t.equals("String")) {
                    params.put(k, parameters.getString(k));
                } else if (t.equals("date")) {
                    if (!"".equals(parameters.getString(k).trim())) {
                        params.put(k, DateTime.stringToCal(parameters.getString(k)));
                    } else {
                        // Fecha vacia sera tomada como opcional
                        params.remove(k);
                        parameters.put(k, "");
                    }
                } else if (t.equals("boolean")) {
                    params.put(k, parameters.getString(k).trim().length() > 0);
                } else if (t.equals("JSONArray")) {
                    params.put("description", null);
                    params.put("duration", null);
                    parameters.put("description", "");
                    parameters.put("duration", "");
                    JSONArray jsonList = parameters.getJSONArray(k);
                    String description = (String) jsonList.get(0);
                    params.put("description", description);
                    parameters.put("description", description);
                    int duration = Integer.parseInt((String) jsonList.get(1));
                    params.put("duration", duration);
                    parameters.put("duration", duration);
                }
            }
        } catch (Exception e) {
            System.out.println("Validation error");
            e.printStackTrace();
        }

        if (params.containsKey("id")) {
            Integer ID = (Integer) params.get("id");
            if (ID == null || ID != null && ID < 0) {
                message.append("La ID no debe ser menor a 0.\n");
            }
        }

        if (params.containsKey("tail-number")) {
            String tailNumber = (String) params.get("tail-number");
            if (tailNumber == null || tailNumber != null && tailNumber.length() != 6) {
                message.append("El formato para el Tail Number es incorrecto.\n");
            }
        }

        if (params.containsKey("delivered")) {
            Boolean delivered = (Boolean) params.get("delivered");
            if (delivered == null) {
                message.append("Se necesita saber si el avión fue entregado.\n");
            }
        }

        String[] dates = {"drop-date", "available-date", "created-from", "created-to",
            "dropped-from", "dropped-to", "available-from", "available-to"
        };
        for (String d : dates) {
            Calendar cal = (Calendar) params.get(d);
            if (params.containsKey(d)) {
                //NOTA: agregar validacion???
                if (cal == null) {
                    message.append("El formato de fecha para '" + d + "' es incorrecto.\n");
                }
            }
        }

        parameters.put("ERROR", message.toString());

        return message.toString().length() == 0;
    }

    public String create(JSONObject parameters) throws JSONException {
        String[] keys = {"delivered", "tail-number", "drop-date", "available-date"};

        if (hasValidParameters(keys, parameters)) {
            String delivered = parameters.getString("delivered");
            boolean isDelivered = (delivered.length() > 0 && !delivered.equals("0"));
            String tailNumber = parameters.getString("tail-number");
            Calendar dropDate = DateTime.stringToCal(parameters.getString("drop-date"));
            Calendar availableDate = DateTime.stringToCal(parameters.getString("available-date"));
            try {
                Equipment eq = new Equipment();
                eq.setTailNumber(tailNumber);
                eq.setDisponible(isDelivered);
                eq.setFechaAlta(DateTime.getToday());
                eq.setFechaDisponibilidad(availableDate);
                eq.setFechaBaja(dropDate);
                ds.saveEquipment(eq);
            } catch (Exception e) {
                parameters.put("ERROR", e.getMessage());
                e.printStackTrace();
            }
        }

        return parameters.toString();
    }

    public static void createMany(JSONArray list) throws JSONException {
        for (int i = 0; i < list.length(); i++) {
            instance.create((JSONObject) list.get(i));
        }
    }

    public String edit(JSONObject parameters) throws JSONException {
        int id = parameters.getInt("id");
        String list = parameters.getString("list");

        return parameters.toString();
    }

    public String remove(JSONObject parameters) throws JSONException {
        int id = parameters.getInt("id");
        try {
            ds.deleteEquipment(id);
        } catch (Exception e) {
            System.out.println("SQL Error");
        }

        return parameters.toString();
    }

    public String getFormattedSuggestions(JSONObject parameters) throws JSONException {
        String searchWords = parameters.getString("searchWords");
        StringBuilder sb = new StringBuilder();

        try {
            List<Equipment> list = ds.retrieveEquipmentsLike(searchWords, "tail-number");
            for (Equipment e : list) {
                sb.append("<li>" + e.getTailNumber() + "</li>");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "<ul>" + sb.toString() + "</ul>";
    }

    public String search(JSONObject parameters) throws JSONException {
        String searchWords = parameters.getString("postData");
        String order = parameters.getString("order");
        List<Equipment> list = new ArrayList();

        list = ds.retrieveEquipmentsLike(searchWords, order);

        return render(list);
    }

    public String advancedSearch(JSONObject parameters) throws JSONException {
        String[] keys = {"delivered", "created-from", "created-to", "dropped-from", "dropped-to", "available-from", "available-to"};
        List<Equipment> list = new ArrayList();

        if (hasValidParameters(keys, parameters)) {
            String delivered = parameters.getString("delivered");
            boolean isDelivered = (delivered.length() > 0 && !delivered.equals("0"));
            Map<String, Object> params = new HashMap();

            params.put("delivered", isDelivered);
            params.put("order", parameters.getString("order"));
            params.put("created-from", DateTime.stringToCal(parameters.getString("created-from")));
            params.put("created-to", DateTime.stringToCal(parameters.getString("created-to")));
            params.put("dropped-from", DateTime.stringToCal(parameters.getString("dropped-from")));
            params.put("dropped-to", DateTime.stringToCal(parameters.getString("dropped-to")));
            params.put("available-from", DateTime.stringToCal(parameters.getString("available-from")));
            params.put("available-to", DateTime.stringToCal(parameters.getString("available-to")));

            list = ds.retrieveEquipmentsInRange(params);

            return render(list);
        } else {
            return parameters.toString();
        }
    }

    public String read(JSONObject parameters) throws JSONException {
        String filter = parameters.getString("filter");
        String order = parameters.getString("order");

        List<Equipment> list = new ArrayList();

        try {
            Map<String, Object> params = new HashMap();

            params.put("order", order);
            if (filter.equals("delivered")) {
                params.put("delivered", true);
            } else if (filter.equals("available")) {
                params.put("available-to", DateTime.getToday());
            } else if (filter.equals("dropped")) {
                params.put("dropped-to", DateTime.getToday());
            } else if (filter.equals("maintenance")) {
                //PENDIENTE
            }
            list = ds.retrieveEquipmentsInRange(params);
        //filter, order: list = ds.retrieveEquipments();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return render(list);
    }

    private String render(List<Equipment> list) throws JSONException {
        JSONObject jsonResponse = new JSONObject();

        jsonResponse.put("render", true);
        jsonResponse.put("items", list);

        return jsonResponse.toString();
    }

    public String assign(JSONObject parameters) throws JSONException {
        int equipmentId = parameters.getInt("equipmentId");
        int maintenanceId = parameters.getInt("maintenanceId");
        Calendar availableTo = DateTime.stringToCal(parameters.getString("limit-date"));
        try {
            EquipmentMaintenance em = new EquipmentMaintenance();
            em.setEquipmentID(equipmentId);
            em.setMaintenanceID(maintenanceId);
            em.setMaintenanceDate(availableTo);
            System.out.println("Aqui llego");
            ds.saveEquipmentMaintenance(em);
            Optimizator opt = Optimizator.getInstance();
            List NotProgrammed = opt.getNotProgrammed();
        } catch (Exception e) {
            System.out.println("Error SQL");
            e.printStackTrace();
        }

        return parameters.toString();
    }
    
    public String getMaintenances(JSONObject parameters) throws JSONException {
        List<Maintenance> lst = factory.retrieveMaintenances("all", "description");
        parameters.put("maintenances", new JSONArray(lst));
        
        return parameters.toString();
    }
    
    public String getEquipmentMaintenances(JSONObject parameters) throws JSONException {
        int equipmentId = parameters.getInt("equipmentId");
        List<EquipmentMaintenance> list = new ArrayList();
        Maintenance m;
        long maintenanceId;
        JSONArray arr = new JSONArray();
        JSONObject obj;
        
        try {
            list = ds.retrieveEquipmentLog(equipmentId);
            for (EquipmentMaintenance em : list) {
                m = factory.retrieveMaintenance(em.getMaintenanceID());
                obj = new JSONObject();
                obj.put("id",  em.getID() );
                obj.put("description", m.getDescription() );
                obj.put("duration",  m.getDuration() );
                obj.put("limit-date", DateTime.calToString(em.getMaintenanceDate()));
                arr.put(obj);
            }
            
        } catch (Exception e) {
            ;
        }
        parameters.put("em", arr);

        return parameters.toString();
    }
}
